/*
* Lingo! t13n.
* - version 0.5
* - author: Vaibhav Vaish : vaibhav.vaish+lingo[@]gmail.com
* - Released under MIT public license.
*
* Copyright (c) <2009> <Vaibhav Vaish>
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
* 
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
* 
* Usage (under default settings):
* 		Load the bookmarklet. On ready, Ctrl+Click and Shift+Ctrl+Click to toggle between the transliterations.
* Settings: 
* lingot13nsettings={
* 			'l': <an array of languages to alternate with in transliteration>
* 				Default value: ['DEVANAGARI','GUJARATI','BENGALI','TAMIL','GURMUKHI','TELUGU','KANNADA','MALAYALAM','ORIYA']
* 			'a': <true or false, if true an alert is issued on load indicating the script is ready, useful for bookmarklets>
* 				Default value: true
* 			'w': <how to process transliterations, can be:
* 						//'bind':translate html at once, but also bind for future clicks.
* 						//'once':translate html at once, no future clicks are noticed.
* 						//'none':translate one tag at a time, as and when clicks occur.
* 				 >
* 				Default value: 'none',//what?
* 			'LIMIT':<Largest string size for a single substitution attempt. 0 to disable>
* 				Default value: 50000
* 			'TIMELAPSE':<Time lapse (ms) between two transliterations (after the LIMIT is exhausted).>
* 				Default value: 100
* 		};
* The variable may not be set at all, or only a few options may be set.
*/


//Remove debug lines via regexp: if\s*\(\s*debug\s*\)\s*\{[^}]*\}
//Resume debug via lines: //(.*if\s*\(\s*debug\s*\)\s*\{[^}]*\})
// and the lines below!
// if (window.opera) {
// 	log = opera.postError;
// } else if (console) {
// 	log = console.log;
// } else {
// 	log = alert;
// }

if (typeof(lingot13nsettings)=="undefined"){ // construct the settings variable if absent.
	lingot13nsettings={};
}

(function(){//initialize settings.
	var defaults={
			'l':['DEVANAGARI','GUJARATI','BENGALI','TAMIL','GURMUKHI','TELUGU','KANNADA','MALAYALAM','ORIYA'],//languages.
			'a':true,//alert? alert on load: useful for bookmarklets.
			'w':'none',//what?
						//'bind':translate html at once, but also bind for future clicks.
						//'once':translate html at once, no future clicks are noticed.
						//'none':translate a tag at a time, as and when clicks occur.
			'r':false,//release jquery when done?
					//'no': do not release
					//true/false: release, with extreme or not as 'r'.
			'LIMIT':50000, //Largest string size for a single substitution attempt. 0 to disable.
			'TIMELAPSE':100, //Time lapse between successive regexp calls.
			'MAXATTEMPTSQUERY':40, //No of times will wait for jquery.
			'TIMELAPSEQUERY':200 //polls for presence of jquery every;
		};
	for (var opt in defaults){
		if (typeof(lingot13nsettings[opt]) == "undefined"){
			lingot13nsettings[opt]=defaults[opt];
		}
	}
})();


(function (settings){
//	/*if (debug){*/var debug = true;/* }*/
	var languages= {
		'DEVANAGARI':{
			'START' :  0x0901, //'DEVANAGARI_SIGN_CANDRABINDU,'
			'END' :  0x096F, //'DEVANAGARI_DIGIT_NINE',
			'UNICODE': '[\\u0901-\\u096F]'
		},
		'GUJARATI':{
			'START' :  0x0A81, //'GUJARATI_SIGN_CANDRABINDU',
			'END' :  0x0AF1, //'GUJARATI_RUPEE_SIGN',
			'UNICODE': '[\\u0A81-\\u0AF1]'
		},
		'BENGALI':{
			'START' :  0x0981, //'BENGALI_SIGN_CANDRABINDU',
			'END' :  0x09FA, //'BENGALI_ISSHAR',
			'UNICODE': '[\\u0981-\\u09FA]'
		},
		'TAMIL':{
			'START' :  0x0B81, //'TAMIL_SIGN_ANUSVARA - 1',
			'END' :  0x0BFA, //'TAMIL_NUMBER_SIGN',
			'UNICODE': '[\\u0B81-\\u0BFA]'
		},
		'GURMUKHI':{
			'START' :  0x0A01, //'GURMUKHI_SIGN_ADAK_BINDI',
			'END' :  0x0A74, //'GURMUKHI_EK_ONKAR',
			'UNICODE': '[\\u0A01-\\u0A74]'
		},
		'TELUGU':{
			'START' :  0x0C01, //'TELUGU_SIGN_CANDRABINDU',
			'END' :  0x0C6F, //'TELUGU_DIGIT_NINE',
			'UNICODE': '[\\u0C01-\\u0C6F]'
		},
		'KANNADA':{
			'START' :  0x0C81, //'KANNADA_SIGN_ANUSVARA - 1',
			'END' :  0x0CEF, //'KANNADA_DIGIT_NINE',
			'UNICODE': '[\\u0C81-\\u0CEF]'
		},
		'MALAYALAM':{
			'START' :  0x0D01, //'MALAYALAM_SIGN_ANUSVARA - 1',
			'END' :  0x0D6F, //'MALAYALAM_DIGIT_NINE',
			'UNICODE': '[\\u0D01-\\u0D6F]'
		},
		'ORIYA':{
			'START' :  0x0B01, //'ORIYA_SIGN_CANDRABINDU',
			'END' :  0x0B71, //'ORIYA_LETTER_WA',
			'UNICODE': '[\\u0B01-\\u0B71]'
		}
	}, LIMIT = 2000, TIMELAPSE = 100,  domsInProgress=[], targetPosition=0, targetLanguageList, $;
	
	function translateString(str,to,limit,initial)
	{
		var lname, lang, changed=false, SHIFT=0;
		function translateMatchedRegex(s){
			changed = true;
			return String.fromCharCode(s.charCodeAt(0) + SHIFT);
		}
		if (!initial) { 
			initial =0;
		}
		if (!limit) {
			limit =str.length();
		}
		str = str.slice(initial,limit);
		for(lname in languages) {
			lang = languages[lname];
			SHIFT = languages[to].START-lang.START;
			str=str.replace(new RegExp(lang.UNICODE,'g'),translateMatchedRegex);
		}
		return {'string':str,'changed':changed,'position':limit};
	}

	function translate() {
		if (!domsInProgress.length) { return;}//nothing to process.
		var current, result, lim, target, textData;
		current = domsInProgress[domsInProgress.length - 1];
		target=$(current.target);
		if (LIMIT>0) {
			lim = current.position + LIMIT;
		} else { lim=current.textLength;}

		if (lim > current.textLength) {
			lim = current.textLength;
		}
		result = translateString(current.oldtext, current.targetLanguage, lim, current.position);
		current.newtext +=result.string;
		current.changed = current.changed || result.changed;
		if (result.position >= current.textLength) {
			if (current.changed) {
				textData = target.data("lingot13nsettings");
				textData[current.targetLanguage] = current.newtext;
				target.data("lingot13nsettings",textData);
				target.html(current.newtext);
			}

			domsInProgress.pop();
		} else {
			current.position = result.position;
		}
		if (domsInProgress.length > 0) {//something remains!
			setTimeout(translate, TIMELAPSE);
		}
	}

	function revert(target) {
//		if (debug) {log("#r reverting html");}
		var data = target.data("lingot13nsettings");
		target.html(data.original); //Revert to original.
	}

	function change(target,position) {
		var data = target.data("lingot13nsettings"), lang=targetLanguageList[position];
//		if (debug) {log("#c will translate", target, " to ",lang, " at ", position);}
		if (typeof(data[lang])=="undefined")
		{
			//actual translation
			data[lang]=false;
			target.data("lingot13nsettings",data);
			domsInProgress.push({
							'target':target,
							'targetLanguage':lang,
							'oldtext':data.original,
							'textLength':data.original.length,
							'position':0,
							'newtext':'',
							'changed':false
			});
			translate();
		} else {
			//Revert to saved copy.
//			if (debug) {log("#c reverting to saved copy");}
			target.html(data[lang]);
		}
	}
	
	function processClick(event) {
		var target=$(event.target), oldtarget, newlang=1;
		if (settings.w == "bind") {target=$("body");}
//		if (debug) {log("#p clicked");}
		if (event.ctrlKey || event.metaKey) {
//			if (debug) {log("#p processing", target);}
			if (event.shiftKey) {
//				if (debug) {log("#p shift active");}
				//Will change the language to previous one if needed.
				newlang= -1;
			}
			if (typeof(target.data("lingot13nsettings"))=="undefined")
			{
				//First click on element.
//				if (debug) {log("#p first click");}
				target.data("lingot13nsettings",{"original":target.html()}).data("lingot13nisLastClicked",true);
				change(target,targetPosition);
				return;
			}
			if (typeof(target.data("lingot13nisLastClicked"))!=="undefined") {
				//Consecutive click. Change languages.
//				if (debug) {log("#p consecutive click");}
				if (target.data("lingot13nisLastClicked")==="reverted") 
				{
					target.data("lingot13nisLastClicked","reset");
				} else {
					targetPosition+=newlang;
				}
				//On the margins
				if (targetPosition>=targetLanguageList.length || targetPosition<0){
					targetPosition-=newlang; //sanitize the variable.
//					if (debug) {log("#p reverting");}
					//Revert to original.
					target.data("lingot13nisLastClicked","reverted");
					revert(target);
					return;
				}
				change(target,targetPosition);
				return;
			} else {
				//Not a new data, but not last clicked either. Just change languages.
//				if (debug) {log("#p will translate");}
				oldtarget=$(document).data("lingot13nlastClicked");
				if (typeof(oldtarget)!=="undefined")
				{
					oldtarget.removeData("lingot13nisLastClicked");
				}
				target.data("lingot13nisLastClicked","first");
				$(document).data("lingot13nlastClicked",target);
				change(target,targetPosition);
			}
		}
	}
	
	function init(){
		var target;
		if (typeof(jQuery)=="undefined") {
//			if (debug) {log("Waiting for jquery ... attempt",settings.MAXATTEMPTSQUERY);}
			if (settings.MAXATTEMPTSQUERY--!==0) {
				setTimeout(init,settings.TIMELAPSEQUERY);
				return;
			}
		}
		$=jQuery;
		if (settings.r!=='no') {$=$.noConflict(settings.r);}
		if (settings.w=="once" || settings.w=="bind") {
			target=$("body");
			target.data("lingot13nsettings",{"original":target.html()});
			change(target,targetPosition);
			if (settings.w=="once") {return;}
		} 
		$(document).bind('click.lingot13n',processClick);
	}

//	if (debug) {log("Initializing ...");}
	targetLanguageList = settings.l;
	LIMIT = settings.LIMIT;
	TIMELAPSE = settings.TIMELAPSE;
	init();
	if (settings.a) {alert("Ready to transliterate in languages:\n"+targetLanguageList.join(",")+".\nUse Ctrl+Click and Shift+Ctrl+Click to toggle between languages.");}
//	if (debug) {log("... ready to transliterate in languages:"+targetLanguageList.join(","));}
})(lingot13nsettings);
